
package pyrachnid.model.robot_model;

import java.awt.Point;
import java.util.ArrayList;

import Event.Operation.OperationRobot;

import pyrachnid.model.ObservableWithEvent;
import pyrachnid.model.ground_model.Cell;
import pyrachnid.model.ground_model.Map;


public class Robot extends ObservableWithEvent<OperationRobot> implements Cloneable {
	private RobotType _robotType;
	private int _positionX;
	private int _positionY;
	private int _oldPositionX;
	private int _oldPositionY;
	private ArrayList<Cell> _route;
	private Cell _allocated;
	private double _nextUpdate;

	private Point _realPosition;
	private ArrayList<Point> _nextPosition;
	private double _xOneCell;
	private double _yOneCell;
	
	
	public Robot(int posX, int posY, RobotType typeRobot){
		_positionX = posX;
		_positionY = posY;
		_oldPositionX = posX;
		_oldPositionY = posY;
		_robotType = typeRobot;
		_allocated = null;
		_route = new ArrayList<Cell>();

		// Compute position
		Map map = Manager.getInstance().getMap();
		_xOneCell = map.getXsize() / map.getXdimension();
		_yOneCell = map.getYsize() / map.getYdimension();
		
		int xPosition = (int) (_positionX * (_xOneCell) + (_xOneCell / 2));
		int yPosition = (int) (_positionY * (_yOneCell) + (_yOneCell / 2));
		_realPosition = new Point(xPosition, yPosition);
		
		_nextPosition = new ArrayList<Point>();
	}
	
	@Override
	public Robot clone() throws CloneNotSupportedException {
		Robot clonedRobot = (Robot) super.clone();
		clonedRobot._robotType = _robotType.clone();
		clonedRobot._route = new ArrayList<Cell>();
		clonedRobot._allocated = null;
		clonedRobot._realPosition = (Point)_realPosition.clone();
		clonedRobot._nextPosition = new ArrayList<Point>();
		return clonedRobot;
	}

	public boolean getIsMoove()
	{
		//System.out.println("allocated : " + getIsAllocated() + "nextposition : " + _nextPosition.size() );
		return getIsAllocated() && _nextPosition.size() > 0;
	}
	
	public Point getRealPosition() {
		return _realPosition;
	}

	public RobotType getRobotType() {
		return _robotType;
	}
	
	public int getPositionX() {
		return _positionX;
	}
	
	public int getPositionY() {
		return _positionY;
	}
	
	public int getOldPositionX() {
		return _oldPositionX;
	}
	
	public int getOldPositionY() {
		return _oldPositionY;
	}

	public void setPosition(int p_posX, int p_posY) {
		this.notifyObserver(this, "Position Change");
		_oldPositionX = _positionX;
		_oldPositionY = _positionY;
		_positionX = p_posX;
		_positionY = p_posY;
	}

	public Cell getAllocateFire() {
		return _allocated;
	}
	
	public void setAllocateFire(Cell p_cell) {
		if(p_cell != null)
		{
			this.notifyObserver(this, "Allocate");
		}
		else
		{
			this.notifyObserver(this, "Not allocate");
			_nextPosition.clear();
		}
		_allocated = p_cell;
	}
	
	
	public boolean getIsAllocated() {
		return _allocated != null;
	}
	

	
	public boolean getCanMoove() {
		return Manager.getInstance().getMap().getGround()[_positionX][_positionY].getGroundValue() <= _robotType.getMaxGroundValue();
	}
	
	public void update(int p_time)
	{
		_nextUpdate -= p_time;
		
		// Arriv� dans la nouvelle case
		if(_nextUpdate <= 0)
		{
			if(getIsAllocated() && _route.size() > 0)
			{
				Cell cellUse = _route.get(0);
				
				if(_route.size() > 1)
				{
					if(cellUse != null)
					{						
						setPosition(cellUse.getPositionX(), cellUse.getPositionY());
						
						// We are in this cell, so we remove it
						_route.remove(0);
						
						// Compute next path
						computeNextPosition();
						
						if(_route.size() == 1) this.notifyObserver(this, "Fire reach");
					}
				}
				else if(_route.size() == 1 && cellUse.getFire() != null)
				{
					cellUse.getFire().decressIntensity(_robotType.getDecressByTop());
				}
				
				if(!_route.get(_route.size() - 1).getIsInFire())
				{
					setAllocateFire(null);
					_route.remove(0);
				}
			}
			if(_route.size() > 1)
			{
				_nextUpdate = timeNextCell();
			}
			else
			{
				_nextUpdate = _robotType.getExtinguishingSpeed();
			}
		}
		
		// Avance la position du robot
		if(getIsAllocated() && _route.size() > 1 && _nextPosition.size() >= 1)
		{
			_realPosition = _nextPosition.get(0);
			_nextPosition.remove(0);
			
			this.notifyObserver(this, "Real Position change");
		}
	}
	
	private void computeNextPosition()
	{
		_nextPosition.clear();
		
		if(_route.size() > 1)
		{
			Cell curentRoute = _route.get(0);
			int nbDeplacement = (int) (timeNextCell() / Manager.getInstance().getScenario().getSpeed());
			
			if(nbDeplacement == 0) nbDeplacement++;

			double x = 0;
			double y = 0;

			double xTarget = curentRoute.getPositionX() * _xOneCell + (_xOneCell / 2);
			double yTarget = curentRoute.getPositionY() * _yOneCell + (_yOneCell / 2);

			double xOneCell = Math.abs((_realPosition.getX() - xTarget) / nbDeplacement);
			double yOneCell = Math.abs((_realPosition.getY() - yTarget) / nbDeplacement);
			
			// -1, 0 or 1
			int xFlag = (_realPosition.getX() < xTarget)? 1 : -1;
			int yFlag = (_realPosition.getY() < yTarget)? 1 : -1;
			
			for(int i = 1; i <= nbDeplacement; i++)
			{
				if(i < nbDeplacement - 1)
				{
					x = _realPosition.getX() + (i * xOneCell * xFlag);
					y = _realPosition.getY() + (i * yOneCell * yFlag);
				}
				else
				{
					x = xTarget;
					y = yTarget;
				}
				_nextPosition.add(new Point((int)(x), (int) (y)));
			}
		}
	}
	
	public double timeNextCell()
	{
		return (_route.size() > 1)? _robotType.getGroundInfluence() * _route.get(0).getGroundValue() : -1;
	}

	public double getTimeToCell(Map p_map, Cell p_cellTarget) {
		double time = 0;
		Cell sourceCell = Manager.getInstance().getMap().getGround()[_positionX][_positionY];
		
		generateRoute(p_map, sourceCell, p_cellTarget);

		if(_route.size() > 0)
		{
			// AU moins 1
			for(int i = 1; i < _route.size(); i++) {
				double value = _route.get(i-1).getGroundValue() * _robotType.getGroundInfluence();
				time += (value > 1)? _route.get(i-1).getGroundValue() * _robotType.getGroundInfluence() : 1;
			}
		}
		else
		{
			time = -1.0;
		}
		
		return time;
	}
	
	private void generateRoute(Map p_map, Cell p_cellSource, Cell p_cellTarget)
	{
		_route = _robotType.getPathFind().getShorterPath(p_map, p_cellSource, p_cellTarget, this);
		
		if(_route.size() > 1)
		{
			// La premi�re case n'est pas acc�d� par le rebot(case de d�part)
			_route.remove(0);
			
			// On initialise le temp pour le premier top
			_nextUpdate = timeNextCell();
			
			// Compute first path
			computeNextPosition();
		}
	}
	
	public ArrayList<Cell> getRoute() {
		return _route;	
	}

	public double getNextUpdate() {
		return _nextUpdate;
	}

}
